package cn.terenas.tool.excel.common.constant;

import cn.terenas.tool.excel.Main;
import cn.terenas.tool.excel.common.enums.result.TransferTypeEnum;
import cn.terenas.tool.excel.common.exception.ExcelException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public class Constant {

    public static final String CONFIG_KEY_PREFIX = "CONFIG_";

    public static final String CONFIG_KEY_CODE_MAPPING = "CONFIG_CODE_MAPPING";

    public static final String CONFIG_KEY_DOMESTIC_AIRPORT_CODE = "CONFIG_DOMESTIC_AIRPORT_CODE";

    public static final String CONFIG_KEY_INTERNATIONAL_AIRPORT_CODE = "CONFIG_INTERNATIONAL_AIRPORT_CODE";

    public static final String CONFIG_KEY_UNION_CODE = "CONFIG_UNION_CODE";

    public static final String CONFIG_KEY_ROW_LIMIT = "CONFIG_ROW_LIMIT";

    public static final Map<String, String> CODE_MAPPING = Maps.newLinkedHashMap();

    public static final Set<String> DOMESTIC_AIRPORT_CODE_SET = Sets.newTreeSet();


    public static final Set<String> INTERNATIONAL_AIRPORT_CODE_SET = Sets.newTreeSet();

    static {
        initDefaultDomesticCodeMapping();
        initDefaultDomesticCode();
        initDefaultInternationalCodeMapping();
        initDefaultInternationalCode();
    }

    private static final String DEFAULT_INTERNATIONAL_MAPPING_CONFIG_PATH = "config/international-mapping.conf";

    private static void initDefaultInternationalCodeMapping() {
        try {
            List<String> mappingList = loadFiles(DEFAULT_INTERNATIONAL_MAPPING_CONFIG_PATH);
            mappingList.stream()
                    .filter(StringUtils::isNotBlank)
                    .forEach(mappingStr -> {
                                int index = mappingStr.indexOf("-");
                                CODE_MAPPING.putIfAbsent(
                                        mappingStr.substring(0, index),
                                        mappingStr.substring(index + 1)
                                );
                            }
                    );
        } catch (Exception e) {
            log.debug(">>> 国际机场编码映射关系初始化错误, e:", e);
            log.error(">>> 国际机场编码映射关系初始化错误, {}, 请联系管理员!", e.getMessage());
            throw new ExcelException("国际机场编码映射关系初始化错误!");
        }
    }

    private static final String DEFAULT_INTERNATIONAL_CODE_CONFIG_PATH = "config/international-code.conf";

    private static void initDefaultInternationalCode() {
        try {
            List<String> mappingList = loadFiles(DEFAULT_INTERNATIONAL_CODE_CONFIG_PATH);
            INTERNATIONAL_AIRPORT_CODE_SET.addAll(
                    mappingList.stream()
                            .filter(StringUtils::isNotBlank)
                            .collect(Collectors.toCollection(Sets::newTreeSet))
            );
        } catch (Exception e) {
            log.debug(">>> 国际机场编码初始化错误, e:", e);
            log.error(">>> 国际机场编码初始化错误, {}, 请联系管理员!", e.getMessage());
            throw new ExcelException("国际机场关系初始化错误!");
        }
    }

    private static final String DEFAULT_DOMESTIC_MAPPING_CONFIG_PATH = "config/domestic-mapping.conf";

    private static void initDefaultDomesticCodeMapping() {
        try {
            List<String> mappingList = loadFiles(DEFAULT_DOMESTIC_MAPPING_CONFIG_PATH);
            mappingList.stream()
                    .filter(StringUtils::isNotBlank)
                    .forEach(mappingStr -> {
                                int index = mappingStr.indexOf("-");
                                CODE_MAPPING.putIfAbsent(
                                        mappingStr.substring(0, index),
                                        mappingStr.substring(index + 1)
                                );
                            }
                    );
        } catch (Exception e) {
            log.debug(">>> 国内机场编码映射关系初始化错误, e:", e);
            log.error(">>> 国内机场编码映射关系初始化错误, {}, 请联系管理员!", e.getMessage());
            throw new ExcelException("国内机场编码映射关系初始化错误!");
        }
    }

    private static final String DEFAULT_DOMESTIC_CODE_CONFIG_PATH = "config/domestic-code.conf";

    private static void initDefaultDomesticCode() {
        try {
            List<String> mappingList = loadFiles(DEFAULT_DOMESTIC_CODE_CONFIG_PATH);
            DOMESTIC_AIRPORT_CODE_SET.addAll(
                    mappingList.stream()
                            .filter(StringUtils::isNotBlank)
                            .collect(Collectors.toCollection(Sets::newTreeSet))
            );
        } catch (Exception e) {
            log.debug(">>> 国内机场关系初始化错误, e:", e);
            log.error(">>> 国内机场关系初始化错误, {}, 请联系管理员!", e.getMessage());
            throw new ExcelException("国内机场关系初始化错误!");
        }
    }

    private static List<String> loadFiles(String path) {
        try (InputStream in = Main.class.getClassLoader().getResourceAsStream(path)) {
            return IOUtils.readLines(Objects.requireNonNull(in), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.debug(">>> 默认配置文件初始化错误, e:", e);
            log.error(">>> 默认配置文件初始化错误, 请联系管理员!");
            throw new RuntimeException("默认配置文件不存在!");
        }

    }


    public static final Set<String> UNION_CODE_SET = Sets.newTreeSet(
            Lists.newArrayList(
                    "AF", "AM", "AR", "AZ", "CI", "DL", "FM", "GA", "KE", "KL",
                    "KQ", "ME", "MF", "MU", "OK", "RO", "SU", "SV", "UX", "VN"
            )
    );


    public static final String SEPARATE_LINE = "----------------------------------------";

    /**
     * ~ (300 * 61.5 ) / 13.5
     */
    public static final short TITLE_ROW_HEIGHT = (short) 1350;

    /**
     * ~ (300 * 19.5) / 13.5
     */
    public static final short DEFAULT_ROW_HEIGHT = (short) 430;


    public static int BREAK = 1;

    public static int TOTAL_AREA_ROW = 1;

    public static int TOTAL_AREA_COL = 0;

    public static final int TOTAL_AREA_WIDTH = 4;

    public static int SIGN_AREA_ROW = 14;

    public static int SIGN_AREA_COL = 0;

    public static final int SIGN_AREA_WIDTH = 4;



    public static int DD_RANK_AREA_ROW = 1;

    public static int DI_RANK_AREA_ROW = 14;

    public static int ID_RANK_AREA_ROW = 27;

    public static int II_RANK_AREA_ROW = 40;

    public static final Map<String, Integer> RANK_AREA_ROW_MAP = Maps.newHashMap();

    static {
        RANK_AREA_ROW_MAP.put(TransferTypeEnum.DD.name(), DD_RANK_AREA_ROW);
        RANK_AREA_ROW_MAP.put(TransferTypeEnum.DI.name(), DI_RANK_AREA_ROW);
        RANK_AREA_ROW_MAP.put(TransferTypeEnum.ID.name(), ID_RANK_AREA_ROW);
        RANK_AREA_ROW_MAP.put(TransferTypeEnum.II.name(), II_RANK_AREA_ROW);

    }
    public static int RANK_AREA_COL = 5;

    public static final int RANK_AREA_WIDTH = 4;

    public static int DOMESTIC_AREA_ROW = 1;

    public static int DOMESTIC_AREA_COL = 10;

    public static final int DOMESTIC_AREA_WIDTH = 9;

    public static int INTERNATIONAL_AREA_ROW = 1;

    public static int INTERNATIONAL_AREA_COL = 20;

    public static final int INTERNATIONAL_AREA_WIDTH = 9;

    public static int UNION_AREA_ROW = 1;

    public static int UNION_AREA_COL = 30;

    public static final int UNION_AREA_WIDTH = 13;

    public static int TITLE_ROW = 0;

    public static int TITLE_COL = 0;

    public static final int TITLE_WIDTH =
            TOTAL_AREA_WIDTH + BREAK
                    + RANK_AREA_WIDTH + BREAK
                    + DOMESTIC_AREA_WIDTH + BREAK
                    + INTERNATIONAL_AREA_WIDTH + BREAK
                    + UNION_AREA_WIDTH;

    public static final int LINE_CHART_AREA_ROW = 1;
    public static final int LINE_CHART_AREA_COL = TITLE_WIDTH + BREAK + 1;
    public static final int LINE_CHART_AREA_WIDTH = 6;

    public static final int AIRPORT_CODE_LENGTH = 3;
    public static final int UNION_CODE_LENGTH = 2;
}
